﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CommonLib {
    public class Orientation {
        public const double Nonexistent = 0.0;
        public const double Exterior = 1.0;
        public const double Interior = -1.0;
    }

    public abstract class Primitive {
        public abstract double isIntersect(Ray r, ref double dist);
        public abstract Vector3c getNormal(Vector3c boundryPoint);
        public abstract Primitive Clone();

        public Material Material { get { return material; } set { material = value; } }
        public bool Light { get { return light; } }

        protected internal Material material;
        protected internal bool light;
    }

    public class Plane : Primitive {
        public Vector3c position;
        public Vector3c direction;

        public Plane(Vector3c pos, Vector3c dir, bool li) {
            this.position = pos;
            this.direction = dir;
            this.direction.normalize();
            this.light = li;
            this.material = Material;
        }
        public Plane(Plane clone) {
            this.position = clone.position;
            this.direction = clone.direction;
            this.light = clone.light;
            this.material = clone.material;
        }
        public override Primitive Clone() {
            return new Plane(this);
        }
        public override double isIntersect(Ray r, ref double dist) {
            //double d = (direction & (position - r.position)) / (direction & r.direction);
            Vector3c v = position;
            v.sub(r.position);
            double d = direction.dot(v) / direction.dot(r.direction);

            if ((0 < d && d < dist) == false)
                return Orientation.Nonexistent;

            dist = d;
            return Orientation.Exterior;
        }
        public override Vector3c getNormal(Vector3c bndry) {
            return direction;
        }
    }

    public class Sphere : Primitive {
        private Vector3c position;
        private double radius;

        public Sphere(Vector3c pos, double rad, bool li) {
            this.position = pos;
            this.radius = rad;
            this.light = li;
            this.material = Material;
        }
        public Sphere(Sphere clone) {
            this.position = clone.position;
            this.radius = clone.radius;
            this.light = clone.light;
            this.material = clone.material;
        }
        public override Primitive Clone() {
            return new Sphere(this);
        }
        public override double isIntersect(Ray r, ref double dist) {
            // dot = (V, Vo - Po)
            // d = dot^2 - |Vo - Po|^2 + r^2 >= 0
            // t- = -dot - Sqrt(d)
            // t+ = -dot + Sqrt(d)
            // P = tV * Vo

          Vector3c v = r.position;
            v.x -= position.x;
            v.y -= position.y;
            v.z -= position.z;

            var p = r.direction;
            double dot = (p.x * v.x) + (p.y * v.y) + (p.z * v.z);
            double vv = (v.x * v.x) + (v.y * v.y) + (v.z * v.z);
            double d = (dot * dot) - vv + (radius * radius);

            if ((d > 0) == false)
                return 0.0;

            d = Math.Sqrt(d);
            double tneg = -dot - d;
            double tpos = -dot + d;
            if (0 < tpos) {
                if (0 < tneg && tneg < dist) {
                    dist = tneg;
                    return Orientation.Exterior;
                }
                if (tneg < 0 && tpos < dist) {
                    dist = tpos;
                    return Orientation.Interior;
                }
            }
            
            return Orientation.Nonexistent;
        }
        public override Vector3c getNormal(Vector3c bndry) {
            // return !(bndry - position);
            Vector3c normal = bndry;
            normal.sub(position);
            normal.normalize();
            return normal;
        }
    }
}
